package com.carb.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carb.constant.JwtConstant;
import com.carb.constant.MessageConstant;
import com.carb.constant.PasswordConstant;
import com.carb.dto.UserAddDTO;
import com.carb.dto.UserLoginDTO;
import com.carb.dto.UserPageQueryDTO;
import com.carb.dto.UserUpdateDTO;
import com.carb.entity.Employee;
import com.carb.entity.User;
import com.carb.enums.*;
import com.carb.exception.AccountDisabledException;
import com.carb.exception.AccountNotFoundException;
import com.carb.exception.DeletionNotAllowedException;
import com.carb.exception.PasswordErrorException;
import com.carb.mapper.EmployeeMapper;
import com.carb.mapper.UserMapper;
import com.carb.properties.JwtProperties;
import com.carb.query.PageQueryUtils;
import com.carb.result.PageResult;
import com.carb.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carb.utils.JwtUtils;
import com.carb.utils.RegexUtils;
import com.carb.vo.UserLoginVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 用户管理 服务实现类
 * </p>
 *
 * @author XuChaoyang
 * @since 2025-01-18
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private EmployeeMapper employeeMapper;


    /**
     * 新增管理员
     * @param userAddDTO 新增管理员信息
     */
    @Override
    @Transactional
    public void addAdmin(UserAddDTO userAddDTO) {
        // 1、正则校验
        // 移动电话
        RegexUtils.checkMobilePhone(userAddDTO.getMobilePhone());
        // 身份证号码
        RegexUtils.checkIdNumber(userAddDTO.getIdNumber());
        // 电子邮箱
        RegexUtils.checkEmail(userAddDTO.getEmail());

        // 2、检查用户是否已经存在且逻辑删除（已删除）
        User isUserExist = this.getOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, userAddDTO.getUsername())
                .eq(User::getDeleted, CommonDeleted.DELETED));
        if (isUserExist != null) {
            // 更新用户逻辑删除为未删除
            BeanUtils.copyProperties(userAddDTO, isUserExist);
            isUserExist.setDeleted(CommonDeleted.NOT_DELETED)
                    .setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.ADMIN_PASSWORD.getBytes()))
                    .setCreateTime(LocalDateTime.now())
                    .setUpdateTime(LocalDateTime.now())
                    .setLastLoginTime(null);
            this.update(isUserExist, Wrappers.lambdaUpdate(User.class)
                    .eq(User::getUsername, userAddDTO.getUsername()));
            // 跳过新增逻辑
            return;
        }

        // 2、用户属性拷贝
        User user = new User();
        BeanUtils.copyProperties(userAddDTO, user);

        // 3、填充用户属性
        // 3.1、设置默认密码admin（MD5加密）
        user.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.ADMIN_PASSWORD.getBytes()));
        // 3.2、设置用户状态，默认为启用状态
        user.setStatus(CommonStatus.ENABLED);
        // 3.3、设置用户角色，当前为管理员
        user.setRole(UserRole.ADMIN);

        // 4、新增管理员
        this.save(user);
    }

    /**
     * 用户登录
     * @param userLoginDTO 用户登录信息
     * @return User实体对象
     */
    @Override
    public UserLoginVO login(UserLoginDTO userLoginDTO) {
        // 1、获取用户名、密码
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();

        // 2、根据用户名查询数据库
        User user = this.getOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, username)
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));

        // 3、校验账号
        // 3.1、判断账号是否存在
        if (user == null) {
            // 用户账号不存在
            throw new AccountNotFoundException(MessageConstant.USER_ACCOUNT_NOT_FOUND);
        }
        // 3.2、判断密码是否正确
        password = DigestUtils.md5DigestAsHex(password.getBytes()); // 密码加密
        if (!password.equals(user.getPassword())) {
            // 密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
        // 3.3、判断用户是否禁用
        if (user.getStatus() == CommonStatus.DISABLED) {
            // 账号禁用
            throw new AccountDisabledException(MessageConstant.ACCOUNT_DISABLED);
        }

        // 4、登录成功，更新上次登录时间
        user.setLastLoginTime(LocalDateTime.now());
        updateById(user);

        // 5、生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtConstant.USER_ID, user.getId()); // 用户id
        // 如果用户角色为员工，需要具体到职位
        String userRole = user.getRole().getDesc();
        if (userRole.equals(UserRole.EMPLOYEE.getDesc())) {
            EmployeePosition position = employeeMapper.selectOne(Wrappers.lambdaQuery(Employee.class)
                    .eq(Employee::getUserId, user.getId())).getPosition();
            userRole = position.getDesc();
        }
        claims.put(JwtConstant.ROLE, userRole); // 用户角色
        String token = JwtUtils.createJWT(
                jwtProperties.getSecretKey(),
                jwtProperties.getTtl(),
                claims);

        // 6、返回用户实体对象
        return UserLoginVO.builder()
                .id(user.getId())
                .userName(user.getUsername())
                .name(user.getName())
                .role(userRole)
                .token(token)
                .build();
    }

    /**
     * 用户分页查询
     * @param userPageQueryDTO 查询条件
     * @return 用户分页查询结果
     */
    @Override
    public PageResult<User> pageQuery(UserPageQueryDTO userPageQueryDTO) {
        // 1、获取查询属性
        Long pageNum = PageQueryUtils.checkPageNum(userPageQueryDTO.getPageNum());
        Long pageSize = PageQueryUtils.checkPageSize(userPageQueryDTO.getPageSize());
        String orderBy = userPageQueryDTO.getOrderBy();
        Boolean isAsc = userPageQueryDTO.getIsAsc();
        // 1.1、分页属性
        String username = userPageQueryDTO.getUsername();
        String name = userPageQueryDTO.getName();
        String mobilePhone = userPageQueryDTO.getMobilePhone();
        CommonStatus status = userPageQueryDTO.getStatus();
        UserRole role = userPageQueryDTO.getRole();

        // 2、构造条件
        // 2.1、分页条件
        Page<User> page = Page.of(pageNum, pageSize);
        // 2.2、排序条件
        PageQueryUtils.applySorting(page, orderBy, isAsc);

        // 3、用户表查询（用户名（非空）、姓名（非空）、移动电话（非空）、用户状态（非空）、用户角色（非空）、逻辑删除（未删除））
        Page<User> userPage = this.page(page, Wrappers.lambdaQuery(User.class)
                .like(username != null, User::getUsername, username)
                .like(name != null, User::getName, name)
                .like(mobilePhone != null, User::getMobilePhone, mobilePhone)
                .eq(status != null, User::getStatus, status)
                .eq(role != null, User::getRole, role)
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));

        // 4、返回封装结果
        return new PageResult<>(userPage.getTotal(), userPage.getPages(), userPage.getRecords());
    }

    /**
     * 启用/禁用用户状态
     * @param id 用户id
     * @param status 用户状态
     */
    @Override
    @Transactional
    public void updateStatus(Long id, CommonStatus status) {
        // 1、检查用户是否存在
        User user = checkUserExist(id);

        // 2、更新
        user.setStatus(status).setUpdateTime(LocalDateTime.now());
        update(user, Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, id));
    }

    /**
     * 根据用户id查询用户信息
     * @param id 用户id
     * @return 查询结果
     */
    @Override
    public User getUserById(Long id) {
        // 1、检查用户是否存在，并返回
        return checkUserExist(id);
    }

    /**
     * 修改用户信息
     * @param userUpdateDTO 修改的用户信息
     */
    @Override
    @Transactional
    public void updateUser(UserUpdateDTO userUpdateDTO) {
        // 1、检查用户是否存在
        Long id = userUpdateDTO.getId();
        User user = checkUserExist(id);

        // 2、用户更新信息（移动电话、身份证号码、电子邮箱需要进行正则校验）
        // 移动电话
        String mobilePhone = userUpdateDTO.getMobilePhone();
        RegexUtils.checkMobilePhone(mobilePhone);
        // 身份证号码
        String idNumber = userUpdateDTO.getIdNumber();
        RegexUtils.checkIdNumber(idNumber);
        // 电子邮箱
        String email = userUpdateDTO.getEmail();
        RegexUtils.checkEmail(email);

        // 2、用户更新
        BeanUtils.copyProperties(userUpdateDTO, user);
        user.setUpdateTime(LocalDateTime.now());
        this.update(user, Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, id));
    }


    /**
     * 删除管理员（不可删除其他类型用户）
     * @param id 用户id
     */
    @Override
    @Transactional
    public void deleteAdmin(Long id) {
        // 1、检查用户是否存在
        User user = checkUserExist(id);

        // 2、判断用户角色是否为管理员
        if (user.getRole() != UserRole.ADMIN) {
            // 不是管理员
            throw new DeletionNotAllowedException(MessageConstant.CAN_NOT_DELETE_NON_ADMIN);
        }

        // 3、更新管理员用户（逻辑删除）
        this.update(new User(), Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, id)
                .set(User::getDeleted, CommonDeleted.DELETED));
    }

    /**
     * 修改用户密码
     * @param id 用户id
     * @param password 新密码
     */
    @Override
    @Transactional
    public void updatePassword(Long id, String password) {
        // 1、检查用户是否存在
        checkUserExist(id);

        // 2、密码正则校验
        RegexUtils.checkPassword(password);
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        // 3、更新用户密码
        this.update(new User(), Wrappers.lambdaUpdate(User.class)
                .eq(User::getId, id)
                .set(User::getPassword, password));
    }

    /**
     * 检查用户是否存在
     * @param userId 用户id
     * @return 用户对象
     */
    private User checkUserExist(Long userId) {
        // 1、检查用户是否存在
        User user = this.getOne(Wrappers.lambdaQuery(User.class)
                .eq(User::getId, userId)
                .eq(User::getDeleted, CommonDeleted.NOT_DELETED));
        if (user == null) {
            // 用户账号不存在，抛出异常
            throw new AccountNotFoundException(MessageConstant.USER_ACCOUNT_NOT_FOUND);
        }
        return user;
    }

}
